/******************************************************************************
 * Copyright (C) 2024 Createtree, Inc.(Gmbh) or its affiliates.
 *
 * All Rights Reserved.
 *
 * @file system_adaption.h
 *
 * @par dependencies
 * - system_adaption.h
 * @author Createtree | R&D Dept. | liuzhihuawy@163.com
 *
 * @brief Intergrate all the resources of system and enable the system to run.
 *
 * Processing flow:
 *
 * call directly.
 *
 * @version V1.0 2024-11-01
 *
 * @note 1 tab == 4 spaces!
 *
 *****************************************************************************/
//******************************** Includes *********************************//
#include "system_adaption.h"

#include "main.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "cmsis_os.h"

#include "bsp_led_driver.h"
#include "bsp_led_handler.h"
//******************************** Includes *********************************//
//******************************** Defines **********************************//
extern int uart_printf(const char *fmt, ...);
#define SYSLOG(str, ...) uart_printf(str, ##__VA_ARGS__)

/* instance */
__attribute__ ((section ("bsp_target_rw")))
bsp_led_handler_t led_handler1 = {SYSTEM_INIT_PATTERN};
__attribute__ ((section ("bsp_target_rw")))
bsp_led_driver_t led_driver1 = {SYSTEM_INIT_PATTERN};
led_id_t hled1;

/* BSP driver interface ---------------------------------*/
led_status_t led1_on(void)
{
    SYSLOG("led on ok\r\n");
    HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
    return LED_STATUS_OK;
}
led_status_t led1_off(void)
{
    SYSLOG("led off ok\r\n");
    HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
    return LED_STATUS_OK;
}
const led_operations_t led1_ops_handle =
{
    .pf_led_on = led1_on,
    .pf_led_off = led1_off
};

led_status_t test_get_time(uint32_t * const ms)
{
    *ms = HAL_GetTick();
    return LED_STATUS_OK;
}
const time_base_t test_time_base_handle =
{
    .pf_get_time = test_get_time
};

led_status_t test_os_sleep(const uint32_t ms)
{
    SYSLOG("sleep %d ms\r\n", ms);
    osDelay(ms);
    return LED_STATUS_OK;
}
const os_sleep_t test_os_sleep_handle =
{
    .pf_sleep = test_os_sleep
};


/* LED Handler interface --------------------------------*/
#ifdef OS_SUPPORTING
led_handler_status_t fn_led_handler1_os_sleep(const uint32_t ms)
{
    osDelay(ms);
    return LED_HANDLER_STATUS_OK;
}
const handler_os_sleep_t led_handler1_os_sleep
= { .pf_sleep = fn_led_handler1_os_sleep};

/* os queue create */
led_handler_status_t fn_led_handler1_os_queue_create (
                                            uint32_t const       cell_num,
                                            uint32_t const      cell_size,
                                            void **  const   queue_handle)
{
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    assert_param(NULL != queue_handle);
    SYSLOG("create queue cell_num:%d, cell_size:%d\r\n",
               cell_num, cell_size);
    QueueHandle_t qh = xQueueCreate(cell_num, cell_size);
    if (qh == NULL)
    {
        SYSLOG("queue create: LED_HANDLER_STATUS_ERROR_RSRC\r\n");
        ret = LED_HANDLER_STATUS_ERROR_RSRC;
    }
    *queue_handle = qh;
    return ret;
}

/* os queue send */
led_handler_status_t fn_led_handler1_os_queue_push  (
                                            void  *   const   queue_handle,
                                            void  *   const            msg,
                                            uint32_t               timeout)
{
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    assert_param(NULL != queue_handle);
    assert_param(NULL != msg);
    SYSLOG("push a massege to queue\r\n");
    BaseType_t state = xQueueSend((QueueHandle_t)queue_handle,
                                  msg,
                                  (TickType_t)timeout);
    if (pdPASS != state)
    {
        SYSLOG("queue send: LED_HANDLER_STATUS_ERROR_RSRC\r\n");
        ret = LED_HANDLER_STATUS_ERROR_RSRC;
    }
    return ret;
}

/* os queue receive */
led_handler_status_t fn_led_handler1_os_queue_pop   (
                                            void  *   const   queue_handle,
                                            void  *   const            msg,
                                            uint32_t               timeout)
{
    led_handler_status_t ret;
    assert_param(NULL != queue_handle);
    assert_param(NULL != msg);
    BaseType_t state = xQueueReceive(queue_handle, msg, timeout);
    if (pdPASS == state)
    {
        ret = LED_HANDLER_STATUS_OK;
    }
    else if (errQUEUE_EMPTY == state)
    {
        SYSLOG("queue pop: LED_HANDLER_STATUS_TIMEOUT\r\n");
        ret = LED_HANDLER_STATUS_TIMEOUT;
    }
    else if (pdFALSE == state)
    {
        SYSLOG("queue pop: LED_HANDLER_STATUS_ERROR_RSRC\r\n");
        ret = LED_HANDLER_STATUS_ERROR_RSRC;
    }
    return ret;
}

/* os queue delete */
led_handler_status_t fn_led_handler1_os_queue_delete (
                                           void  *   const   queue_handle)
{
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    assert_param(NULL != queue_handle);
    vQueueDelete((QueueHandle_t)queue_handle);
    return ret;
}

const handler_os_queue_op_t led_handler1_os_queue_op =
{
    .pf_os_queue_create = fn_led_handler1_os_queue_create,
    .pf_os_queue_push   = fn_led_handler1_os_queue_push,
    .pf_os_queue_pop    = fn_led_handler1_os_queue_pop,
    .pf_os_queue_delete = fn_led_handler1_os_queue_delete
};

/* entry critical section */
void fn_led_handler1_os_critical_enter (void)
{
    // TODO: if already in critical section, returm error
    SYSLOG("enter critical section\r\n");
    vPortEnterCritical();
}
/* exit critical section */
void fn_led_handler1_os_critical_exit  (void)
{
    // TODO: if already in critical section, returm error
    vPortExitCritical();
    SYSLOG("exit critical section\r\n");
}
const handler_os_critial_t led_handler1_os_critical =
{
    .pf_os_critical_enter = fn_led_handler1_os_critical_enter,
    .pf_os_critical_exit  = fn_led_handler1_os_critical_exit
};

/* os thread create */
led_handler_status_t fn_led_handler1_os_therad_create (
                        void *   const       task_fn,
                        const char        *task_name,
                        uint32_t const    stack_size,
                        void *   const    parameters,
                        uint32_t const      priority,
                        void **  const   task_handle)
{
    BaseType_t state;
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    assert_param(NULL != task_fn);
    assert_param(NULL != task_name);
    assert_param(0    != stack_size);
    assert_param(NULL != task_handle);

    state = xTaskCreate((TaskFunction_t)task_fn,
                        task_name,
                        stack_size,
                        parameters,
                        priority,
                        (TaskHandle_t *)task_handle);
    if (pdPASS != state)
    {
        ret = LED_HANDLER_STATUS_ERROR_RSRC;
        SYSLOG("create thread failed\r\n");
    }
    return ret;
}
/* os thread delete */
led_handler_status_t fn_led_handler1_os_thread_delete (
                        void *   const   task_handle)
{
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    assert_param(NULL != task_handle);
    vTaskDelete(task_handle);
    return ret;

}
const handler_os_thread_op_t led_handler1_os_thread_op =
{
    .pf_os_thread_create = fn_led_handler1_os_therad_create,
    .pf_os_thread_delete = fn_led_handler1_os_thread_delete
};
#endif /* OS_SUPPORTING */
led_handler_status_t fn_led_handler1_get_time(uint32_t * const ms)
{
    assert_param(NULL != ms);
    *ms = xTaskGetTickCount();
    return LED_HANDLER_STATUS_OK;
}
const handler_time_base_t led_handler1_time_base = 
{
    .pf_get_time = fn_led_handler1_get_time
};

#ifdef SYSTEM_UNIT_TESTING
void test_led_driver(void)
{
    bsp_led_driver_t led1_driver;
    bsp_led_constructor(&led1_driver,
                        &led1_ops_handle,
                        &test_os_sleep_handle,
                        &test_time_base_handle);

    led1_driver.pf_led_ctrl(&led1_driver, 10, 4, LED_DUTY_CYCLE_25);
}


void test_led_handler(void)
{
    SYSLOG("[test] test_led_handler start\r\n");
    SYSLOG("---------------------------------------------------\r\n");
    led_handler_status_t ret = LED_HANDLER_STATUS_OK;
    led_status_t drv_status = LED_STATUS_OK;
    drv_status = bsp_led_constructor(&led_driver1,
                                     &led1_ops_handle,
                                     &test_os_sleep_handle,
                                     &test_time_base_handle);
    if (drv_status != LED_STATUS_OK)
    {
        SYSLOG("[test] led driver constructor failed\r\n");
    }
    ret = led_handler_constructor(&led_handler1,
                                  &led_handler1_os_sleep,
                                  &led_handler1_os_queue_op,
                                  &led_handler1_os_critical,
                                  &led_handler1_os_thread_op,
                                  &led_handler1_time_base);
    if (ret != LED_HANDLER_STATUS_OK)
    {
        SYSLOG("[test] led handler constructor failed\r\n");
    }
    ret = led_handler1.pf_led_register(&led_handler1, &led_driver1, &hled1);
    if (ret != LED_HANDLER_STATUS_OK)
    {
        SYSLOG("[test] led handler register failed\r\n");
    }
    ret = led_handler1.pf_led_ctrl(&led_handler1,
                                   10,
                                   2,
                                   LED_DUTY_CYCLE_50,
                                   hled1);
    if (ret != LED_HANDLER_STATUS_OK)
    {
        SYSLOG("[test] led handler ctrl failed\r\n");
    }
    SYSLOG("[test] led_handler test success\r\n");
}
#endif  /* SYSTEM_UNIT_TESTING */

system_status_t system_adaption_init(void)
{
//***************************** Driver Handler ******************************//
    system_status_t ret = SYSTEM_STATUS_OK;
    led_handler_status_t hdl_status = LED_HANDLER_STATUS_OK;
    led_status_t drv_status = LED_STATUS_OK;

    SYSLOG("---------------------------------------------------\r\n");
    SYSLOG("[sys] System_adaption_init start\r\n");
    drv_status = bsp_led_constructor(&led_driver1,
                                     &led1_ops_handle,
                                     &test_os_sleep_handle,
                                     &test_time_base_handle);
    if (drv_status != LED_STATUS_OK)
    {
        SYSLOG("[sys] led driver constructor failed\r\n");
    }
    hdl_status = led_handler_constructor(&led_handler1,
                                         &led_handler1_os_sleep,
                                         &led_handler1_os_queue_op,
                                         &led_handler1_os_critical,
                                         &led_handler1_os_thread_op,
                                         &led_handler1_time_base);
    if (hdl_status != LED_HANDLER_STATUS_OK)
    {
        SYSLOG("[sys] led handler constructor failed\r\n");
    }
    hdl_status = led_handler1.pf_led_register(&led_handler1,
                                              &led_driver1,
                                              &hled1);
    if (hdl_status != LED_HANDLER_STATUS_OK)
    {
        SYSLOG("[sys] led handler register failed\r\n");
    }

    SYSLOG("[sys] System_adaption_init success\r\n");
    SYSLOG("---------------------------------------------------\r\n");
    return ret;
}

//******************************** Defines **********************************//
//******************************** Declaring ********************************//

//******************************** Declaring ********************************//
